﻿using System;
using System.Collections.Generic;
using System.Text;
using eKanBan.Model;
using System.Globalization;

namespace eKanBan
{
    class ConsoleDemo
    {
        private KanbanBoard board;

        public ConsoleDemo()
        {
            board = new KanbanBoard("BeginPhase", "EndPhase");
            bool quit = false;
            while (!quit)
            {
                int choice = ShowMenu();
                Console.WriteLine();
                switch (choice)
                {
                    case 1:
                        ListPhase();
                        break;
                    case 2:
                        DefineNewPhase();
                        break;
                    case 3:
                        RemovePhase();
                        break;
                    case 4:
                        ViewPhaseDetail();
                        break;
                    case 5:
                        UpdatePhase();
                        break;
                    case 6:
                        AddAMove();
                        break;
                    case 7:
                        RemoveAMove();
                        break;
                    case 8:
                        ListMember();
                        break;
                    case 9:
                        AddNewMember();
                        break;
                    case 10:
                        RemoveMember();
                        break;
                    case 11:
                        UpdateMember();
                        break;

                    case 12:
                        ListFeature();
                        break;
                    case 13:
                        DefineNewFeature();
                        break;
                    case 14:
                        RemoveFeature();
                        break;
                    case 15:
                        UpdateFeature();
                        break;
                    case 16:
                        MoveFeature();
                        break;
                    case 17:
                        ListTask();
                        break;
                    case 18:
                        DefineNewTask();
                        break;
                    case 19:
                        RemoveTask();
                        break;
                    case 20:
                        UpdateTask();
                        break;
                    case 21:
                        SaveToFile();
                        break;
                    case 22:
                        LoadFromFile();
                        break;
                    case 23:
                        quit = true;
                        break;
                }
                Console.Write("Press any key to continue ...");
                Console.ReadKey();

            }
        }

        public int ShowMenu()
        {
            System.Console.WriteLine("\n\neKanban Console Demo");
            System.Console.WriteLine("====================");
            System.Console.WriteLine("1. List Phases");
            System.Console.WriteLine("2. Define new Phase");
            System.Console.WriteLine("3. Remove a Phase");
            System.Console.WriteLine("4. View Phase Detail");
            System.Console.WriteLine("5. Update a Phase");
            System.Console.WriteLine("6. Add a move");
            System.Console.WriteLine("7. Remove a move");
            System.Console.WriteLine("8. List Member");
            System.Console.WriteLine("9. Add new Member");
            System.Console.WriteLine("10. Remove a Member");
            System.Console.WriteLine("11. Update Member");
            System.Console.WriteLine("12. List Feature");
            System.Console.WriteLine("13. Add new Feature");
            System.Console.WriteLine("14. Remove a Feature");
            System.Console.WriteLine("15. Update a Feature");
            System.Console.WriteLine("16. Move Feature to Phase");
            System.Console.WriteLine("17. List Task");
            System.Console.WriteLine("18. Add Task");
            System.Console.WriteLine("19. Remove Task");
            System.Console.WriteLine("20. Update Task");
            System.Console.WriteLine("21. Save to file");
            System.Console.WriteLine("22. Load from file");
            System.Console.WriteLine("23. Quit");
            System.Console.WriteLine("Please choose a task: ");
            string num;
            int choice;
            do
            {
                System.Console.Write("Task #: ");
                num = System.Console.ReadLine();
            } while (!int.TryParse(num, out choice));

            return choice;
        }

        public void DefineNewPhase()
        {
            System.Console.Write("Phase Name: ");
            string name = System.Console.ReadLine();
            System.Console.Write("Definition of done: ");
            string defOfDone = System.Console.ReadLine();
            int numOfMaxFeature = 0;
            string numMax;
            do
            {
                System.Console.Write("Number of max feature: ");
                numMax = System.Console.ReadLine();
            } while (!int.TryParse(numMax, out numOfMaxFeature));

            board.DefineNewPhase(name, defOfDone, numOfMaxFeature);
        }

        public void UpdatePhase()
        {
            BasePhase p = GetPhaseFromConsole("Phase # to remove: ");
            System.Console.Write("Phase Name: ");
            string name = System.Console.ReadLine();
            System.Console.Write("Definition of done: ");
            string defOfDone = System.Console.ReadLine();
            int numOfMaxFeature = 0;
            string numMax;
            do
            {
                System.Console.Write("Number of max feature: ");
                numMax = System.Console.ReadLine();
            } while (!int.TryParse(numMax, out numOfMaxFeature));
            if (p == board.BeginPhase || p == board.EndPhase)
            {
                System.Console.WriteLine("Cannot udpate Begin Phase or End Phase");
            }
            else
            {
                board.UpdatePhase((Phase)p, name, defOfDone, numOfMaxFeature);
            }

        }

        public void RemovePhase()
        {

            BasePhase p = GetPhaseFromConsole("Phase # to remove: ");

            if (p == board.BeginPhase || p == board.EndPhase)
            {
                System.Console.WriteLine("Cannot remove Begin Phase or End Phase");
            }
            else
            {
                board.RemovePhase((Phase)p);
            }
        }

        public void ListPhase()
        {
            System.Console.WriteLine("Phases List");
            System.Console.WriteLine(board.ViewBoard());
        }

        public void ViewPhaseDetail()
        {
            System.Console.WriteLine(board.ViewPhase(GetPhaseFromConsole("Phase # to view: ")));
        }

        public BasePhase GetPhaseFromConsole(string message)
        {
            string phaseId;
            int id;
            do
            {
                ListPhase();
                System.Console.Write(message);
                phaseId = System.Console.ReadLine();
            } while (!int.TryParse(phaseId, out id) || (id < 0 || id > board.PhaseCount + 1));

            return board.GetPhaseById(id);
        }

        public void ListMember()
        {
            System.Console.WriteLine("Members List");
            int count = 0;
            foreach (Member mem in board.Members)
            {
                System.Console.WriteLine(String.Format("#{0}\t{1}\t{2}\t{3}", ++count, mem.Name,
                    mem.Sex ? "Male" : "Female", mem.Comment));
            }
        }

        public Member GetMemberFromConsole(string message)
        {
            string memId;
            int id;
            do
            {
                ListMember();
                System.Console.Write(message);
                memId = System.Console.ReadLine();
            } while (!int.TryParse(memId, out id) || (id <= 0 || id > board.Members.Count));

            return board.Members[id - 1];
        }

        public void AddAMove()
        {
            System.Console.WriteLine("Add a move from phase to phase");
            BasePhase phaseFrom = GetPhaseFromConsole("Phase # from: ");
            BasePhase phaseTo = GetPhaseFromConsole("Phase # to: ");

            try
            {
                board.DefineAMove(phaseFrom, phaseTo);
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.Message);
            }
        }

        public void RemoveAMove()
        {
            System.Console.WriteLine("Remove a move from phase to phase");
            BasePhase phaseFrom = GetPhaseFromConsole("Phase # from: ");
            BasePhase phaseTo = GetPhaseFromConsole("Phase # to: ");

            board.RemoveNextToPhase(phaseFrom, phaseTo);
        }

        public void AddNewMember()
        {
            System.Console.WriteLine("Add new Member");
            System.Console.Write("Member's name: ");
            string name = System.Console.ReadLine();
            System.Console.Write("Member's sex (b/g): ");
            string sex = System.Console.ReadLine();
            System.Console.Write("Member's comment: ");
            string cmt = System.Console.ReadLine();
            bool bSex = sex.Equals("b");

            board.DefineNewMember(name, bSex, cmt);
        }

        public void RemoveMember()
        {
            Member memToRemove = GetMemberFromConsole("Member # to remove: ");
            board.Remove(memToRemove);
        }

        public void UpdateMember()
        {
            Member memToUpdate = GetMemberFromConsole("Member # to update: ");
            System.Console.Write("Member's name: ");
            string name = System.Console.ReadLine();
            System.Console.Write("Member's sex (b/g): ");
            string sex = System.Console.ReadLine();
            System.Console.Write("Member's comment: ");
            string cmt = System.Console.ReadLine();
            bool bSex = sex.Equals("b");
            board.UpdateMember(memToUpdate, name, bSex, cmt, null);
        }

        public void SaveToFile()
        {
            System.Console.WriteLine("Save to file");
            System.Console.Write("File's name: ");
            string filename = System.Console.ReadLine();
            try
            {
                KanbanBoard.Save(filename, board);
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Error Saving: " + e.Message);
            }
        }

        public void LoadFromFile()
        {
            System.Console.WriteLine("Load from file");
            System.Console.Write("File's name: ");
            string filename = System.Console.ReadLine();
            try
            {
                board = KanbanBoard.Load(filename);
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Error Loading: " + e.Message);
            }
        }
        public void ShowFeatures(IList<Feature> list)
        {
            int count = 0;
            System.Console.WriteLine("Feature List");
            foreach (Feature item in list)
            {
                System.Console.WriteLine(String.Format("#{0}\tFeature {0}: {1} - {2}", ++count, item.CurrentPhase.Name, item.Description));
            }
        }
        private void ListFeature()
        {
            ShowFeatures(board.Features);
        }

        private void DefineNewFeature()
        {
            System.Console.Write("Description: ");
            string des = Console.ReadLine();
            int priority = 0;
            string numPriority;
            do
            {
                System.Console.Write("Priority: ");
                numPriority = System.Console.ReadLine();
            } while (!int.TryParse(numPriority, out priority));

            board.DefineNewFeature(des, priority);
        }

        private Feature GetFeatureFromConsole(string message)
        {
            IList<Feature> list = board.Features;
            string phaseId;
            int id;
            do
            {
                ShowFeatures(list);
                System.Console.Write(message);
                phaseId = System.Console.ReadLine();
            } while (!int.TryParse(phaseId, out id) || (id <= 0 || id > list.Count));

            return list[id - 1];
        }

        private void UpdateFeature()
        {
            Feature f = GetFeatureFromConsole("Feature # to update: ");
            System.Console.Write("Description: ");
            string des = Console.ReadLine();
            int priority = 0;
            string numPriority;
            do
            {
                System.Console.Write("Priority: ");
                numPriority = System.Console.ReadLine();
            } while (!int.TryParse(numPriority, out priority));

            board.UpdateFeature(f, des, priority, f.Done);
        }
        private void RemoveFeature()
        {
            Feature f = GetFeatureFromConsole("Feature # to remove: ");
            try
            {
                board.RemoveFeature(f);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error while removing feature: " + e.Message);
            }
        }
        private void MoveFeature()
        {
            Feature f = GetFeatureFromConsole("Feature # to move: ");
            BasePhase p = GetPhaseFromConsole("Phase # of destination: ");
            try
            {
                board.MoveFeature(f, p);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error while moving feature: " + e.Message);
            }
        }

        public void ShowTasks(IList<Task> list)
        {
            int count = 0;
            System.Console.WriteLine("Task List");
            foreach (Task item in list)
            {
                System.Console.WriteLine(String.Format("#{0}\tTask {0}: {1} - {2} - {3}", ++count, item.Feature.CurrentPhase.Name, item.Feature.Description, item.Description));
            }
        }
        private void ListTask()
        {
            ShowTasks(board.Tasks);
        }

        public DateTime GetDateFromConsole(string message)
        {
            DateTime res;
            CultureInfo info = CultureInfo.CreateSpecificCulture("vi");
            DateTimeFormatInfo dinfo = new DateTimeFormatInfo();
            dinfo.ShortDatePattern = "dd/MM/yyyy";
            info.DateTimeFormat = dinfo;
            
            string text = String.Empty;
            do
            {
                System.Console.Write(message);
                text = System.Console.ReadLine();
            } while (!DateTime.TryParse(text, info, DateTimeStyles.AssumeLocal, out res));
            return res;
        }

        private Task.StatusType GetStatusTypeFromConsole(string message)
        {
            string phaseId;
            int id;
            string[] op = Enum.GetNames(typeof(Task.StatusType));
            do
            {
                Console.WriteLine("Status type: ");
                int count = 0;
                foreach (string item in op)
                {
                    count++;
                    System.Console.WriteLine(String.Format("#{0}\t {1}", count, item));
                }
                System.Console.Write(message);
                phaseId = System.Console.ReadLine();
            } while (!int.TryParse(phaseId, out id) || (id <= 0 || id > 4));
            return (Task.StatusType)Enum.Parse(typeof(Task.StatusType), op[id-1]);
        }
        private void DefineNewTask()
        {
            Feature f = GetFeatureFromConsole("Choose the feature that new task is associated with: ");
            System.Console.Write("Description: ");
            string des = Console.ReadLine();
            int priority = 0;
            string numPriority;
            do
            {
                System.Console.Write("Priority: ");
                numPriority = System.Console.ReadLine();
            } while (!int.TryParse(numPriority, out priority));

            Task.StatusType status = GetStatusTypeFromConsole("Status type: ");
            DateTime deadline = GetDateFromConsole("Deadline: ");
            board.DefineNewTask(f, des, priority, status, deadline);
        }

        private Task GetTaskFromConsole(string message)
        {
            IList<Task> list = board.Tasks;
            string phaseId;
            int id;
            do
            {
                ShowTasks(list);
                System.Console.Write(message);
                phaseId = System.Console.ReadLine();
            } while (!int.TryParse(phaseId, out id) || (id <= 0 || id > list.Count));

            return list[id - 1];
        }

        private void RemoveTask()
        {
            Task t = GetTaskFromConsole("Task # to remove: ");
            try
            {
                board.RemoveTask(t);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error while removing task: " + e.Message);
            }
        }
        private void UpdateTask()
        {
            Task t = GetTaskFromConsole("Task # to update: ");

            System.Console.Write("Description: ");
            string des = Console.ReadLine();
            int priority = 0;
            string numPriority;
            do
            {
                System.Console.Write("Priority: ");
                numPriority = System.Console.ReadLine();
            } while (!int.TryParse(numPriority, out priority));

            Task.StatusType status = GetStatusTypeFromConsole("Status type: ");
            DateTime starttime = GetDateFromConsole("Start Time: ");
            DateTime finishtime = GetDateFromConsole("Finish Time: ");
            DateTime deadline = GetDateFromConsole("Deadline: ");

            board.UpdateTask(t, des, priority, status, deadline, starttime, finishtime);
        }
    }
}
